use super::{club_form::ClubFormModel, user::SimpleUserModel, Assets, ClubFormStatusFlow};
use chrono::{DateTime as CDateTime, Utc};
use serde::{Deserialize, Serialize};
use wither::{
    bson::Bson,
    mongodb::bson::{oid::ObjectId, DateTime, Document},
    Model,
};

/// ## ClubFormStatusHistory
/// 修改状态所产生的记录
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ClubFormStatusHistory {
    pub op_id: ObjectId,
    pub op_name: String,
    pub op_avatar: Option<Assets>,
    pub op_time: DateTime,
    pub from: ClubFormStatusFlow,
    pub to: ClubFormStatusFlow,
}

impl ClubFormStatusHistory {
    pub fn new<
        F: Into<ClubFormStatusFlow>,
        T: Into<ClubFormStatusFlow>,
        U: Into<SimpleUserModel>,
    >(
        from: F,
        to: T,
        user: U,
    ) -> Self {
        let mut from: ClubFormStatusFlow = from.into();
        let mut to: ClubFormStatusFlow = to.into();
        let user: SimpleUserModel = user.into();
        from.children.clear();
        to.children.clear();
        Self {
            op_id: user.id,
            op_name: user.nickname,
            op_avatar: user.avatar,
            op_time: DateTime::now(),
            from,
            to,
        }
    }
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ClubFormStatusHistoryDTO {
    pub op_id: String,
    pub op_name: String,
    pub op_avatar: Option<Assets>,
    pub op_time: CDateTime<Utc>,
    pub from: ClubFormStatusFlow,
    pub to: ClubFormStatusFlow,
}

impl From<ClubFormStatusHistory> for ClubFormStatusHistoryDTO {
    fn from(h: ClubFormStatusHistory) -> Self {
        Self {
            op_id: h.op_id.to_string(),
            op_name: h.op_name,
            op_avatar: h.op_avatar,
            op_time: h.op_time.to_chrono(),
            from: h.from,
            to: h.to,
        }
    }
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UserApplicationSourceForm {
    #[serde(default = "Default::default")]
    pub title: String,
    pub description: Option<String>,
    pub rule: Option<Document>,
    pub layout: Option<Document>,
}
impl UserApplicationSourceForm {
    pub fn from_form(form: &ClubFormModel) -> Self {
        Self {
            title: form.title.clone(),
            description: form.description.clone(),
            rule: form.rule.clone(),
            layout: form.layout.clone(),
        }
    }
}
#[derive(Debug, Clone, Serialize, Deserialize, Model)]
pub struct UserApplicationModel {
    #[serde(rename = "_id", skip_serializing_if = "Option::is_none")]
    pub id: Option<ObjectId>,
    pub user_id: ObjectId,
    pub form_id: ObjectId,
    pub club_id: Option<ObjectId>,
    pub content: Bson,
    /// 状态流的头部
    pub status_header: Option<ClubFormStatusFlow>,
    pub status: Option<ClubFormStatusFlow>,
    pub status_history: Vec<ClubFormStatusHistory>,
    pub source_form: UserApplicationSourceForm,
    pub created_at: DateTime,
    pub updated_at: DateTime,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UserApplicationModelDTO {
    pub id: Option<String>,
    pub user_id: String,
    pub form_id: String,
    pub club_id: Option<String>,
    pub content: Bson,
    pub status: Option<ClubFormStatusFlow>,
    pub status_history: Vec<ClubFormStatusHistoryDTO>,
    pub source_form: UserApplicationSourceForm,
    pub created_at: CDateTime<Utc>,
    pub updated_at: CDateTime<Utc>,
}

impl From<UserApplicationModel> for UserApplicationModelDTO {
    fn from(model: UserApplicationModel) -> Self {
        Self {
            id: model.id.as_ref().map(ObjectId::to_string),
            user_id: model.user_id.to_string(),
            form_id: model.form_id.to_string(),
            club_id: model.club_id.as_ref().map(ObjectId::to_string),
            content: model.content,
            status: model.status,
            status_history: model
                .status_history
                .iter()
                .map(|h| ClubFormStatusHistoryDTO::from(h.clone()))
                .collect(),
            source_form: model.source_form,
            created_at: model.created_at.to_chrono(),
            updated_at: model.updated_at.to_chrono(),
        }
    }
}
